import React, { Component } from "react";
import "../App.css";
import Figure2D from "./Figure2D";
import { POINT_TYPE } from "./Canvas2DItem";

// 随机点类型
function randomPointType(){
  const n = Object.keys(POINT_TYPE).length;

  return Math.floor( Math.random()*n );
}
// 随机颜色
function randomColor(){
  let color = '';
  while(color.length < 6){
    color += '0123456789abcdef'[Math.floor(Math.random()*16)];
  }

  return `#${color}`;
}

// 生成随机点样式字典
function createRandomPointStyleDict(labels){
  let pointStyleDict = {};
  for(let i=0, il=labels.length; i < il; i++){
    if(labels[i] in pointStyleDict) continue;
    pointStyleDict[labels[i]] = {
      type : randomPointType(),
      color: randomColor(),
      size : 5,
    };
  }
  return pointStyleDict;
}

class MatView2D extends Component{
  constructor(props){
    super(props);

    const width  = props.Width  ? props.Width :640;
    const height = props.Height ? props.Height:480;
    this.state={
      mat       : [],           // 矩阵数据
      labels    : [],           // 标签数据，决定画图中点的类型和颜色

      separator       : {},           // 分割线/超平面
      highLightPoints : [],      // 高亮点列表
      highLightType   : 0,
      highLightSize   : 8,
      highLigntColor  : '#ff0000',
      
      pointStyleDict   : {},    // 点类型字典，应用存储显示点的样式、颜色、大小等属性
      matColLabels     : [],    // 矩阵列标签
      selectedValueX   : '',    // x数据源来自矩阵哪一列
      selectedValueY   : '',    // y数据源来自矩阵哪一列

      width     : width,        // 图宽度
      height    : height,       // 图高度
      xRange    : props.XRange, // X范围
      yRange    : props.YRange, // Y范围
      pointSize : 5,

      showLabelSetting : false,
    }

    this.handleValueChanged   = this.handleValueChanged.bind(this);
    this.updatePointStyleDict = this.updatePointStyleDict.bind(this);

    this.figure    = new Figure2D( width, height );

    this.refFigure = React.createRef();
    this.xScource  = React.createRef();
    this.yScource  = React.createRef();
  }

  componentDidMount(){
    // 添加图到页面
    this.refFigure.current.appendChild(this.figure.domElement);
    this.figure.update();
    // 初始化矩阵列标签
    let matColLabels    = this.props.MatColLabels;
    let pointStyleDict  = this.props.PointStyleDict;
    let mat             = this.props.Mat;
    let labels          = this.props.Labels;
    let separator       = this.props.Separator;
    let highLightPoints = this.props.HighLightPoints;

    if(!mat || mat.cols() < 2) return;

    if(!matColLabels){
      matColLabels = [];
      for(let i=0,il=mat.cols();i<il;i++){
        matColLabels.push(i.toString());
      }
    }
    // 随机生成一个点字典
    if(!pointStyleDict){
      // 有标签属性
      if(labels){
        pointStyleDict = {};
        for(let i=0, il=labels.length; i < il; i++){
          if(labels[i] in pointStyleDict) continue;
          pointStyleDict[labels[i]] = {
            type : randomPointType(),
            color: randomColor(),
            size : this.state.pointSize,
          };
        }
      }
      else{
        pointStyleDict = {};
        labels = [];
      }
    }
    // 添加默认点样式和高亮点样式
    pointStyleDict['default']={
      type : POINT_TYPE.Filled_Circle,
      color: '#000000',
      size : this.state.pointSize,
    };
    pointStyleDict['highLight']={
        type : POINT_TYPE.Circle,
        color: '#000000',
        size : this.state.pointSize * 2,
    };

    // 分割超平面参数信息

    this.setState({
      mat            : mat,
      labels         : labels,
      separator      : separator,
      highLightPoints: highLightPoints,

      pointStyleDict : pointStyleDict,
      matColLabels   : matColLabels,
      
      selectedValueX : matColLabels[0],
      selectedValueY : matColLabels[1],
    })
  }

  handleValueChanged(event){
    const id    = event.target.id;
    const index = event.target.selectedIndex;
    const value = event.target.value;
    const maxIndex = this.state.matColLabels.length;
    switch(id){
      case 'sw-label':
        this.setState({
          showLabelSetting:event.target.checked
        })
        break;
      case 'X-source': 
        if(value === this.state.selectedValueY){
          let selectedValueY = this.state.matColLabels[(index + 1)%maxIndex];
          this.setState({
            selectedValueX : value,
            selectedValueY: selectedValueY,
          })
        }
        else{
          this.setState({ selectedValueX : value });
        }
        break;
      case 'Y-source': 
        if(value === this.state.selectedValueX){
          let selectedValueX = this.state.matColLabels[(index + 1)%maxIndex];
          this.setState({
            selectedValueX : selectedValueX,
            selectedValueY : value,
          })
        }
        else{
          this.setState({ selectedValueY: value });
        }
        break;
      default:break;
    }

  }

  updatePointStyleDict(event){
    const label = event.target.id;
    const key   = event.target.name;

    let value = event.target.value;

    const pointStyleDict = this.state.pointStyleDict;

    if(key === 'type'){
      value = parseInt(value);
      
      if(isNaN(value) || value < 0 || value >= Object.keys(POINT_TYPE).length){
        event.target.value = 0;
        return;
      }
    }

    if(key === 'size'){
      value = parseInt(value);
      if(isNaN(value) || value <= 3 || value >= 50){
        event.target.value = 3;
        return;
      }
    }

    pointStyleDict[label][key] = value;

    this.setState({
      pointStyleDict: pointStyleDict
    })
  }

  componentDidUpdate(){
    this.updateFigure();
  }

  // 更新图
  updateFigure(){
    const mat          = this.state.mat;
    const labels       = this.state.labels;
    const pointStyleDict    = this.state.pointStyleDict;
    const matColLabels = this.state.matColLabels;
    const xIndex       = this.xScource.current.selectedIndex;
    const yIndex       = this.yScource.current.selectedIndex;
    const separator    = this.state.separator;
    const hihighLightPoints = this.state.highLightPoints;

    const datX      = mat.slice(-1, xIndex); // mat.col(xIndex);
    const datY      = mat.slice(-1, yIndex); // mat.col(yIndex);
    // 更新图显示范围和坐标轴显示标签
    this.figure.xMax = this.state.xRange? this.state.xRange[1]:Math.max(...datX);
    this.figure.xMin = this.state.xRange? this.state.xRange[0]:Math.min(...datX);
    this.figure.xAxisLabel = matColLabels[xIndex];

    this.figure.yMax = this.state.yRange? this.state.yRange[1]:Math.max(...datY);
    this.figure.yMin = this.state.yRange? this.state.yRange[0]:Math.min(...datY);
    this.figure.yAxisLabel = matColLabels[yIndex];

    // 清空图并添加点
    this.figure.clearAll();
    for(let i = 0, il = datX.length; i < il; i++){
      const px = parseFloat(datX[i]);
      const py = parseFloat(datY[i]);

      let pointType;
      const label = labels[i]; 

      if(label in pointStyleDict){             
        pointType   = pointStyleDict[label];
      }
      else{
        pointType   = pointStyleDict['default'];
      }

      this.figure.addPoint(px, py, pointType.size, pointType.type, pointType.color);
      if(hihighLightPoints){
        if(i in hihighLightPoints){
          this.figure.addPoint(px, py, pointStyleDict['highLight'].size, pointStyleDict['highLight'].type, pointStyleDict['highLight'].color);
        }
      }
    }

    // 绘制分割超平面
    if(separator){
      if(separator.type === 'line'){
        const w1 = separator.w[0];
        const w2 = separator.w[1];
        const b  = separator.b;

        let x1, y1;
        let x2, y2;
        // 横线
        if(w1 === 0 && w2 !== 0 && b !== 0){
          x1 = this.figure.xMin;
          y1 = -b / w2;
          x2 = this.figure.xMax;
          y2 = -b / w2;
        }
        // 竖线
        else if(w1 !== 0 && w2 === 0 && b !== 0){
          x1 = -b / w1;
          y1 = this.figure.yMin;
          x2 = -b / w1;
          y2 = this.figure.yMax;
        }
        else if (w1 !== 0 && w2 !== 0 && b !== 0){
          x1 = this.figure.xMin;
          y1 = (-b - w1 * x1) / w2;
 
          x2 = this.figure.xMax;
          y2 = (-b - w1*x2) / w2;
        }

        // 添加线到图
        this.figure.addLine([x1, y1], [x2, y2]);
      }
    }

    this.figure.update();
  }

  _renderPointStyleDict(){
    const pointStyleDict = this.state.pointStyleDict;
    const lables = Object.keys(pointStyleDict);
    return lables.map((item, key)=>{
      const label = item;
      const type  = pointStyleDict[item].type;
      const color = pointStyleDict[item].color;
      const size  = pointStyleDict[item].size;
      return (
        <div className="row" key={key}>
          <div className="col">{label}</div>
          <div className="col">
            <input type='color' defaultValue={color} id={item} name='color'
            onChange={this.updatePointStyleDict}></input>
          </div>
          <div className="col">
            <input type='number' defaultValue={type} id={item} name='type'
            onChange={this.updatePointStyleDict} max={Object.keys(POINT_TYPE).length} min={0}></input>
          </div>
          <div className="col">
            <input type='number' defaultValue={size} id={item} name='size'
            onChange={this.updatePointStyleDict} max={50} min={3}></input>
          </div>
        </div>
      );
    })
  }

  render(){
    return(
      <div>
        <div>
          <label>X轴数据源:</label>
          <select value={this.state.selectedValueX} id='X-source' ref={this.xScource} onChange={this.handleValueChanged}>
            {this.state.matColLabels.map((item, key)=><option key={key}>{item}</option>)}
          </select>
          <label>Y轴数据源:</label>
          <select value={this.state.selectedValueY} id='Y-source' ref={this.yScource} onChange={this.handleValueChanged}>
            {this.state.matColLabels.map((item, key)=><option key={key}>{item}</option>)}
          </select>
          显示标签设置<input id="sw-label" type='checkbox' onChange={this.handleValueChanged}/>
        </div>
        {this.state.showLabelSetting?
          <div className="div-table">
            <div className="row">
              <div className="col">标签</div>
              <div className="col">颜色</div>
              <div className="col">类型</div>
              <div className="col">大小</div>
            </div>
            {this._renderPointStyleDict()}
          </div>
        :''}
        <div ref={this.refFigure}></div>
      </div>
    );
  }
}


export default MatView2D;
export {
  createRandomPointStyleDict
};